package cn.xsshome.imagetool.convert;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;

/**
 * Description 图片转字符工具类
 * ProjectName imagetool
 * Created by 小帅丶 on 2022-07-27
 * Version 1.0
 */

public class ImageToASCII {

    /**
     * @Description 返回默认灰度的字符串
     * @param imagePath - 图片路径
     * @Author 小帅丶
     * @Date  2022/7/27 10:29
     * @return java.lang.String
     **/
    public static String convert(String imagePath) throws Exception {
        BufferedImage image = ImageIO.read(new File(imagePath));
        return convert(false, image);
    }

    /**
     * @Description 返回某一种灰度字符串
     * @param negative - 灰度类型 false 如果灰度值非常高，则像素非常明亮并指定字符 true 反之
     * @param imagePath - 图片路径
     * @Author 小帅丶
     * @Date  2022/7/27 10:29
     * @return java.lang.String
     **/
    public static String convert(boolean negative,String imagePath) throws Exception {
        BufferedImage image = ImageIO.read(new File(imagePath));
        return convert(negative, image);
    }

    /**
     * @Description 返回默认灰度的字符串
     * @param image - BufferedImage
     * @Author 小帅丶
     * @Date  2022/7/27 10:29
     * @return java.lang.String
     **/
    public static String convert(BufferedImage image) {
        return convert(false, image);
    }

    /**
     * @Description 返回某一种灰度字符串
     * @param negative - 灰度类型 false 如果灰度值非常高，则像素非常明亮并指定字符 true 反之
     * @param image - BufferedImage
     * @Author 小帅丶
     * @Date  2022/7/27 10:29
     * @return java.lang.String
     **/
    public static String convert(boolean negative,BufferedImage image) {
        StringBuilder sb = new StringBuilder((image.getWidth() + 1) * image.getHeight());
        for (int y = 0; y < image.getHeight(); y++) {
            if (sb.length() != 0) sb.append("\n");
            for (int x = 0; x < image.getWidth(); x++) {
                Color pixelColor = new Color(image.getRGB(x, y));
                double gValue = (double) pixelColor.getRed() * 0.2989
                        + (double) pixelColor.getBlue() * 0.5870
                        + (double) pixelColor.getGreen() * 0.1140;
                final char s = negative ? returnStrNeg(gValue) : returnStrPos(gValue);
                sb.append(s);
            }
        }
        return sb.toString();
    }

    /**
     * @Description 返回默认灰度字符串
     * @param imagePath - 图片路径
     * @Author 小帅丶
     * @Date  2022/7/27 10:40
     * @return java.awt.image.BufferedImage
     **/
    public static BufferedImage convertToBufferImage(String imagePath) throws Exception {
        BufferedImage image = ImageIO.read(new File(imagePath));
        return convertToBufferImage(false,image);
    }

    /**
     * @Description 返回某一种灰度字符串
     * @param negative - 灰度类型 false 如果灰度值非常高，则像素非常明亮并指定字符 true 反之
     * @param imagePath - 图片路径
     * @Author 小帅丶
     * @Date  2022/7/27 10:40
     * @return java.awt.image.BufferedImage
     **/
    public static BufferedImage convertToBufferImage(boolean negative,String imagePath) throws Exception {
        BufferedImage image = ImageIO.read(new File(imagePath));
        return convertToBufferImage(negative,image);
    }

    /**
     * @Description 返回默认灰度字符串
     * @param image - BufferedImage
     * @Author 小帅丶
     * @Date  2022/7/27 10:40
     * @return java.awt.image.BufferedImage
     **/
    public static BufferedImage convertToBufferImage(BufferedImage image) {
        return convertToBufferImage(false,image);
    }

    /**
     * @Description 返回某一种灰度字符串
     * @param negative - 灰度类型 false 如果灰度值非常高，则像素非常明亮并指定字符 true 反之
     * @param image - BufferedImage
     * @Author 小帅丶
     * @Date  2022/7/27 10:29
     * @return java.awt.image.BufferedImage
     **/
    public static BufferedImage convertToBufferImage(boolean negative,BufferedImage image) {
        BufferedImage bufferedImage = new BufferedImage(image.getWidth(),image.getHeight(),BufferedImage.TYPE_INT_RGB);
        // 获取图像上下文
        Graphics g = createGraphics(bufferedImage, image.getWidth(), image.getHeight());
        for (int y = image.getMinY(); y < image.getHeight(); y++) {
            for (int x = image.getMinX(); x < image.getWidth(); x++) {
                Color pixelColor = new Color(image.getRGB(x, y));
                double gValue = (double) pixelColor.getRed() * 0.2989
                        + (double) pixelColor.getBlue() * 0.5870
                        + (double) pixelColor.getGreen() * 0.1140;
                char s = negative ? returnStrNeg(gValue) : returnStrPos(gValue);
                // 设置字体
                Font font = new Font("Monospaced", Font.BOLD, 5);
                // 设置前景色
                g.setColor(Color.red);
                g.setFont(font);
                g.drawString(String.valueOf(s), x, y);
            }
        }
        return bufferedImage;
    }


    /**
     * 创建一个新字符串，并根据灰度值为其指定一个字符串
     * 如果灰度值非常高，则像素非常明亮并指定字符
     * 例如。而且，这看起来不是很暗。如果灰度值非常低，则像素非常暗，
     * 指定 #和@ 等看起来非常暗的字符
     * @param g grayscale 灰度
     * @return char 字符串
     */
    private static char returnStrPos(double g) {
        final char str;
        if (g >= 230.0) {
            str = ' ';
        } else if (g >= 200.0) {
            str = '.';
        } else if (g >= 180.0) {
            str = '*';
        } else if (g >= 160.0) {
            str = ':';
        } else if (g >= 130.0) {
            str = 'o';
        } else if (g >= 100.0) {
            str = '&';
        } else if (g >= 70.0) {
            str = '8';
        } else if (g >= 50.0) {
            str = '#';
        } else {
            str = '@';
        }
        return str;
    }

    /**
     * 与 returnStrPos 正好相反
     *
     * @param g grayscale 灰度
     * @return char 字符串
     */
    private static char returnStrNeg(double g) {
        final char str;

        if (g >= 230.0) {
            str = '@';
        } else if (g >= 200.0) {
            str = '#';
        } else if (g >= 180.0) {
            str = '8';
        } else if (g >= 160.0) {
            str = '&';
        } else if (g >= 130.0) {
            str = 'o';
        } else if (g >= 100.0) {
            str = ':';
        } else if (g >= 70.0) {
            str = '*';
        } else if (g >= 50.0) {
            str = '.';
        } else {
            str = ' ';
        }
        return str;
    }

    /**
     * 画板默认一些参数设置
     *
     * @param image  图片
     * @param width  图片宽
     * @param height 图片高
     * @return
     */
    private static Graphics createGraphics(BufferedImage image, int width,
                                           int height) {
        Graphics g = image.createGraphics();
        // 设置背景色
        g.setColor(Color.WHITE);
        // 绘制背景
        g.fillRect(0, 0, width, height);
        return g;
    }
}
